﻿package social.VKontakte
{	
	import com.junkbyte.console.Cc;
	
	import vk.APIConnection;
	import vk.events.CustomEvent;
	
	import social.VKontakte.VKFlashVars;
	import social.VKontakte.VKUserRequest;
	import social.SocialDataEvent;
	
	import flash.events.EventDispatcher;	
	import flash.display.Stage;		
	import flash.events.Event;
	import flash.events.ErrorEvent;
	import flash.utils.Timer;
	import flash.events.TimerEvent;	
	import flash.net.URLLoader;
	import flash.net.URLRequest;
	import vk.api.serialization.json.JSON;
		
	public class VKProvider extends EventDispatcher
	{
		private const CRequestsTimer:int = 370;		
		private var FFlashVars:VKFlashVars;
		private var FLoadedVars:Object;
		private var FConnection:APIConnection;
		private var FReqestsDone:int;
		private var FRequestTimer:Timer;
		private var FRequests:Vector.<VKRequest>;
		private var FAutorizationPHP:String;
		private var FRequestPHP:String;
		
		public function VKProvider(AStage:Stage):void
		{			
			FLoadedVars = AStage.loaderInfo.parameters as Object;
			FFlashVars = new VKFlashVars(FLoadedVars, true);
			
			Cc.log('Test mode: ' + FFlashVars.TestMode);
			Cc.log('User: ' + FFlashVars.ViewerID);
			Cc.log('Session ID: ' + FFlashVars.SessionID);
			Cc.log('Secret: ' + FFlashVars.Secret);
						
			FRequestTimer = new Timer(CRequestsTimer);
			FRequestTimer.addEventListener(TimerEvent.TIMER, OnTimer);
			
			FRequests = new Vector.<VKRequest>;
			
			Cc.addSlashCommand('appBalance', RequestAppBalance, 'VK: Getting application balance');
			Cc.addSlashCommand('transferVoices', TransferVoices, 'VK: Opening voices transfer window');
			Cc.addSlashCommand('withdrawVoices', RequestWithdrawVoices, 'VK: withdrawing voices to app admin');
			
		}
		
		private function OnTimer(e:TimerEvent):void
		{
			if(FRequests.length > 0)			
				with(FRequests.shift())						
					Process(FConnection);							
		}
		
		public function Connect():void
		{
			FConnection = new APIConnection(FLoadedVars);
			
			FConnection.addEventListener("onBalanceChanged", OnBalanceChanged);
			FRequestTimer.start();
		}
		
		public function AddRequest(ARequest:VKRequest):void
		{
			FRequests.push(ARequest);
			Cc.log('Request added to quee: ' + ARequest.toString());
		}
		
		// ============================================== RequestUserInfo =================================================== //
		
		public function RequestUserInfo(ARequest:VKUserRequest):void
		{			
			var vRequest:VKRequest = new VKRequest();
			vRequest.Method = 'getProfiles';
			vRequest.Data = ARequest;
			vRequest.OnComplete = OnProfileLoaded;
			vRequest.OnError = OnConnectionError;
			AddRequest(vRequest);
		}
		
		private function OnProfileLoaded(AData:Object):void
		{
			var vEvent:VKProfileEvent = new VKProfileEvent();
			vEvent.Data = new VKUserInfo(AData[0]);
			dispatchEvent(vEvent);
		}
		
		private function OnConnectionError(AData:Object):void
		{
			var vEvent:ErrorEvent = new ErrorEvent(VKEvents.VK_CONNECTION_ERROR);
			try
			{
				vEvent.text = AData.error_msg;
			}
			catch(e:Error)
			{
				vEvent.text = e.message;
			}
			dispatchEvent(vEvent);
		}
		
		// ============================================== RequestUserInfo =================================================== //
		
		// ============================================== VoicesTransfer ==================================================== //
		
		public function TransferVoices(ACount:int = 0):void
		{
			FConnection.callMethod('showPaymentBox', ACount);
		}
		
		//Method called when user balance on current app changed, but voices are not transfered to app admin yet.
		private function OnBalanceChanged(e:CustomEvent):void
		{
			Cc.info('VK: Balance changed. Now = '  + e.params[0]);
			DispatchSocialEvent(VKEvents.VK_BALANCE_CHANGED, e.params[0]);
		}
		
		public function RequestAppBalance():void
		{
			var vRequest:VKRequest = new VKRequest();
			vRequest.Method = 'getUserBalance';
			vRequest.Data = new VKAppBalanceRequest();
			vRequest.OnComplete = OnAppBalance;
			vRequest.OnError = OnCommonError;
			AddRequest(vRequest);
		}
		
		private function OnAppBalance(AData:Object):void			
		{			
			Cc.log('VK: App balance = ' + AData.toString());
			DispatchSocialEvent(VKEvents.VK_APP_BALANCE, AData);
		}
		
		public function RequestWithdrawVoices(ACount:int = 0):void
		{			
			var vURL:String = FRequestPHP + 
			'?uid=' + UserID +
			'&method=secure.withdrawVotes' + 
			'&params=' + 'votes,' + ACount;
			
			Cc.logch('VKProvider', 'Starting transfer');
				
			var vLoader:URLLoader = new URLLoader();
			vLoader.addEventListener(Event.COMPLETE, OnMethodLoaded);
			
			if(FFlashVars.ServerKey != '')
			{
				Cc.logch('VKProvider', 'Server key is ' + FFlashVars.ServerKey);
				vURL += '&access_token=' + FFlashVars.ServerKey;
				vLoader.load(new URLRequest(vURL));				
			}
			else
			{
				Cc.logch('VKProvider', 'Server key is unknown, requesting now');
				FFlashVars.addEventListener(VKFlashVars.SERVER_KEY_LOADED, OnKeyLoaded);
				FFlashVars.LoadServerKey(FAutorizationPHP);
			}
			
			function OnKeyLoaded(e:Event):void			
			{
				FFlashVars.removeEventListener(VKFlashVars.SERVER_KEY_LOADED, OnKeyLoaded);
				
				vURL += '&access_token=' + FFlashVars.ServerKey;
				Cc.logch('VKProvider',' URL: ' + vURL);
				
				vLoader.load(new URLRequest(vURL));
			}
			
			function OnMethodLoaded(e:Event):void
			{
				Cc.log(e.target.data);
				
				var vResponse:Object = JSON.decode(e.target.data);	
				
				if (!vResponse.error)		
					DispatchSocialEvent(VKEvents.VK_VOICES_WITHDRAWED, vResponse.response);
				else
				{
					var vEvent:ErrorEvent = new ErrorEvent(VKEvents.VK_ERROR);
					vEvent.text = vResponse.error.error_msg;
					dispatchEvent(vEvent);
					Cc.error('VK Error: ' + vEvent.text);
				}
			}
		}
		
		public function DirectTransfer(ACount:int):void
		{
			RequestAppBalance();
			addEventListener(VKEvents.VK_APP_BALANCE, OnDirectAppBalance);
			
			var vCount:Number;
			
			function OnDirectAppBalance(e:SocialDataEvent):void
			{
				removeEventListener(VKEvents.VK_APP_BALANCE, OnDirectAppBalance);
				
				vCount = new Number(e.Data) / 100;
				if(vCount >= ACount)
				{
					RequestWithdrawVoices(ACount * 100);
				}
				else
				{
					TransferVoices(ACount - vCount);
					addEventListener(VKEvents.VK_BALANCE_CHANGED, OnDirectBalanceChanged);
				}
			}
			
			function OnDirectBalanceChanged(e:SocialDataEvent):void
			{
				removeEventListener(VKEvents.VK_BALANCE_CHANGED, OnDirectBalanceChanged);
				
				var vNewBalance:int = int(e.Data);
				if(vNewBalance / 100 >= ACount)
				{
					RequestWithdrawVoices(ACount * 100);
				}
				else
				{
					DispatchSocialEvent(VKEvents.VK_VOICES_NEEDED, vNewBalance / 100 -  ACount);
				}
			}
		}
		
		// ============================================== VoicesTransfer ==================================================== //
		
		// ================================================ ServerTime ====================================================== //
				
		public function RequestTime():void
		{
			var vRequest:VKRequest = new VKRequest();
			vRequest.Method = 'getServerTime';
			vRequest.Data = new VKAPIRequest();
			vRequest.OnComplete = OnServerTime;
			vRequest.OnError = OnCommonError;
			AddRequest(vRequest);
		}
		
		private function OnServerTime(AData:Object):void
		{
			DispatchSocialEvent(VKEvents.VK_SERVER_TIME, AData);
		}		
		
		// ================================================ ServerTime ====================================================== //
		
		private function DispatchSocialEvent(AType:String, AData:Object):void
		{
			var vEvent:SocialDataEvent = new SocialDataEvent(AType);
			vEvent.Data = AData;
			dispatchEvent(vEvent);
		}
		
		private function OnCommonError(AData:Object):void
		{
			var vEvent:ErrorEvent = new ErrorEvent(VKEvents.VK_ERROR);
			try
			{
				vEvent.text = AData.error_msg;
			}
			catch(e:Error)
			{
				vEvent.text = e.message;
			}
			dispatchEvent(vEvent);
			
			Cc.error('VK Error: ' + vEvent.text);
		}
		
		public function get UserID():String
		{
			return FFlashVars.ViewerID;
		}		
		
		public function get TestMode():Boolean
		{
			return FFlashVars.TestMode;
		}
		
		public function set AutorizationScript(AURL:String):void
		{
			FAutorizationPHP = AURL;
		}
		
		public function set SecurityRequestsScript(AURL:String):void
		{
			FRequestPHP = AURL;
		}
	}	
}
